using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using RFS.BizLogic.PaiShi.Ports;
using RFS.BizLogic.utils;
using RFS.Domain.PaiShi.Zuhuo;
using RFS.Domain.Sys;
using ycx;

namespace ItProto1
{
    public class ZuhuoManager : IZuhuoManager
    {
        private IRepoZahua _rza;
        private IRepoZuhuaPort _rzu;
        private DateTime _workingDay = DateTime.Today.AddDays(-1);
        private ConcurrentDictionary<ulong, ZuhuaRecord> _zuHuoItems = new ConcurrentDictionary<ulong, ZuhuaRecord>();
        private ConcurrentDictionary<ulong, ZaHuaItem> _zaHuaItems = new ConcurrentDictionary<ulong, ZaHuaItem>();

        public bool ZuLoaded { get; set; } = false;
        public bool ZaLoaded { get; set; } = false;

        public bool LoadedBoth
        {
            get => ZaLoaded && ZuLoaded;
        }


        public ZuhuoManager(IRepoZahua rza, IRepoZuhuaPort rzu, ILog log, IConfigT config)
        {
            _rzu = rzu;
            _log = log;
            _config = config;
            this._rza = rza;

             
            _rzu.RegsiterManager(this);
        }

        public DateTime WorkingDay
        {
            get => _workingDay;
            set
            {
                // if (_workingDay.Date == value.Date) return;
                _workingDay = value;
                OnDayChanged();
            }
        }


        #region DayChanged

        event EventHandler _DayChanged;

        public event EventHandler DayChanged
        {
            add
            {
                _DayChanged += value;
                OnDayChanged();
            }
            remove => _DayChanged -= value;
        }

        void OnDayChanged()
        {
            _DayChanged?.Invoke(this, EventArgs.Empty);


            1.DebounceExecute(() =>
            {
                LoadZaHuaSetAsync();
                LoadZuHuaSetAsync();
            }, 100, "wd");
        }

        #endregion


        #region ZaHuaDataChanged

        event EventHandler<IEnumerable<ZaHuaItem>> _ZaHuaDataChanged;

        public event EventHandler<IEnumerable<ZaHuaItem>> ZaHuaDataChanged
        {
            add
            {
                _ZaHuaDataChanged += value;
                OnZaHuaDataChanged();
            }
            remove => _ZaHuaDataChanged -= value;
        }

        void OnZaHuaDataChanged()
        {
            _ZaHuaDataChanged?.Invoke(this, _zaHuaItems.Values);
            ZaLoaded = true;
            UpdateRelatedZahuaItems(_zuHuoItems.Values);
        }

        #endregion


        #region ZuhuaDataChanged

        event EventHandler<IEnumerable<ZuhuaRecord>> _ZuhuaDataChanged;

        public event EventHandler<IEnumerable<ZuhuaRecord>> ZuhuaDataChanged
        {
            add
            {
                _ZuhuaDataChanged += value;
                OnZuhuaDataChanged();
            }
            remove => _ZuhuaDataChanged -= value;
        }

        void OnZuhuaDataChanged()
        {
            _ZuhuaDataChanged?.Invoke(this, _zuHuoItems.Values);
            ZuLoaded = true;
            UpdateRelatedZahuaItems(_zuHuoItems.Values);
        }

        void UpdateRelatedZahuaItems(IEnumerable<ZuhuaRecord> zs)
        {
            if (!LoadedBoth) return;

            foreach (var za in _zaHuaItems.Values)
            {
                //za.指令时间 = null;
                za.RemoveZuhua();
            }

            foreach (var z in zs)
            {
                foreach (var zu in z.FaHuoZiLingItems)
                {
                    if (_zaHuaItems.ContainsKey(zu.ZaHuaItemId ))
                    {
                        var za = _zaHuaItems[zu.ZaHuaItemId];
                        za.LinkTo(zu, z);
                        zu.ZaHuaItem = za;
                    }
                }
            }

            _ZaHuaDataChanged?.Invoke(this, _zaHuaItems.Values);
            _ZuhuaDataChanged?.Invoke(this, _zuHuoItems.Values);
        }

        #endregion


        public IEnumerable<ZaHuaItem> ZaHuaItems
        {
            get => _zaHuaItems.Values;
            private set
            {
                // _zaHuaItems =
                //     new ConcurrentDictionary<ulong, ZaHuaItem>(value.ToDictionary(x => x.Id, y => y));
                
                _zaHuaItems.Clear();
                foreach (var za in value)
                {
                    _zaHuaItems[za.Id] = za;
                }
                OnZaHuaDataChanged();
            }
        }

        public IEnumerable<ZuhuaRecord> ZuHuoItems
        {
            get => _zuHuoItems.Values;
            private set
            {
                _zuHuoItems = new ConcurrentDictionary<ulong, ZuhuaRecord>(
                    value.ToDictionary(x => x.Id, y => y)
                );
                OnZuhuaDataChanged();
            }
        }

        private ILog _log;
        private IConfigT _config;

        public async Task<IEnumerable<ZaHuaItem>> LoadZaHuaSetAsync(DateTime date = default(DateTime),
            bool includeHistLeftOver = false)
        {
            return await Task.Run(() =>
            {
                if (date == default(DateTime)) date = WorkingDay;
                var re = _rza.GetRecordsByDay(WorkingDay, includeHistLeftOver);

                ZaHuaItems = re;
                // OnZaHuaDataChanged();
                _log.Info($"【{_workingDay:d}】扎花 已完成加载【{ZaHuaItems.Count()}】项！");
                return ZaHuaItems;
            });
        }

        public void CreateAllZuhuo(List<ZaHuaItem> selectedObjects, bool alsosave = true, bool alsoFuzu = true)
        {
            $"加载中, 请稍等。".Required(LoadedBoth);
            selectedObjects = selectedObjects.Where(x => x.ZhiLingItemId == 0).ToList();
            $"请选择扎花。".Required(selectedObjects.Count() > 0);

            _log.Info("");
            _log.Info("开始组花");

            var g = _rzu.BuildGroupZuhuo(selectedObjects);
            var res = _rzu.CreateZuhuoPlans(g, ZuHuoType.首次组花, alsosave);

            foreach (var zr in res.succ)
            {
                _zuHuoItems[zr.Id] = zr;
            }

            OnZaHuaDataChanged();
            
            _log.Info(
                $"一次组货成功【{res.succ.SelectMany(x => x.FaHuoZiLingItems).Count()}】扎花,【{res.succ.Count}】条发货单已生成。其中：失败并有余花【{res.failed.Count}】扎。");


            if (alsoFuzu)
            {
                CreateFuZuhuo(res.failed, alsosave);
            }
            
            _log.Info("组花结束。");

        }


        public async Task SaveZahsAsync()
        {
            await Task.Run(() =>
            {
                if (_config.ConfigSys.SaveAlsoZuhua)
                    _rza.SaveEntitysAsync(_zaHuaItems.Values.Where(x => x.Changed));
            });
        }

        private async Task LongTask(Func<Task> actAsync)
        {
            // Store the original cursor to restore it later.

            try
            {
                // Change the cursor to a wait cursor for the form.
                Cursor.Current = Cursors.WaitCursor;

                // Run the long task asynchronously if actAsync is not null.
                if (actAsync != null)
                {
                    await actAsync();
                }
            }
            finally
            {
                // Ensure that we change the cursor back to its original state, even if an error occurs.
                Cursor.Current = Cursors.Default;
                 
            }
        }


        void LongTask(Action act)
        {
            // Change the cursor to a wait cursor.
            Cursor.Current = Cursors.WaitCursor;

            try
            {
                // Run the long task asynchronously.
                act?.Invoke();
            }
            finally
            {
                // Ensure that we change the cursor back to default, even if an error occurs.
                Cursor.Current = Cursors.Default;
            }
        }

        public async Task SaveAllAsync(IEnumerable<ZuhuaRecord> os = null)
        {
            $"加载中，请稍等".Required(LoadedBoth);


            var src = os ?? _zuHuoItems.Values;

            Cursor.Current = Cursors.WaitCursor;
            await _rzu.SaveAsync(src);
            Cursor.Current = Cursors.Default;

            // await SaveZahsAsync();
        }

        public async Task<IEnumerable<ZaHuaItem>> LoadZuHuaSetAsync(DateTime date = default(DateTime))
        {
            return await Task.Run(() =>
            {
                if (date == default(DateTime)) date = WorkingDay;
                var z = _rzu.GetZuhuaRecordsByDay(WorkingDay);

                _zuHuoItems = new ConcurrentDictionary<ulong, ZuhuaRecord>(
                    z.ToDictionary(x => x.Id, y => y)
                );

                OnZuhuaDataChanged();
                _log.Info($"【{_workingDay:d}】组花数据，已完成加载【{_zuHuoItems.Count()}】项！");

                return ZaHuaItems;
            });
        }

        public void CreateFuZuhuo(List<ZaHuaItem> selectedObjects, bool save = false)
        {
            $"加载中, 请稍等。".Required(LoadedBoth);
            selectedObjects = selectedObjects.Where(x => x.ZhiLingItemId == 0).ToList();
            $"请选择扎花。".Required(selectedObjects.Count() > 0);

            #region secondtry

            var g = _rzu.BuildGroupZuhuo(selectedObjects.Where(x => x.ZhiLingItemId == 0), ZuHuoType.二次组花);
            var res = _rzu.CreateZuhuoPlans(g, ZuHuoType.二次组花, save);

            foreach (var z in res.succ)
            {
                _zuHuoItems[z.Id] = z;
            }

            _log.Info(
                $"二次组花成功【{res.succ.SelectMany(x => x.FaHuoZiLingItems).Count()}】扎花,【{res.succ.Count}】条发货单已生成。其中：失败并余花【{res.failed.Count}】扎。");

            #endregion

            #region third try

            if (res.failed.Any())
            {
                g = _rzu.BuildGroupZuhuo(res.failed, ZuHuoType.三次组花);
                res = _rzu.CreateZuhuoPlans(g, ZuHuoType.三次组花, save);

                foreach (var z in res.succ)
                {
                    _zuHuoItems[z.Id] = z;
                }

                _log.Info(
                    $"三次成功【{res.succ.SelectMany(x => x.FaHuoZiLingItems).Count()}】扎花,【{res.succ.Count}】条发货单已生成。其中：失败并余花【{res.failed.Count}】扎。");
            }

            #endregion


            OnZuhuaDataChanged();
        }

        public void SyncZahuaProductionData()
        {
            Task.Run(() =>
            {
                var newItems = _rza.SyncZahuaDataFromProductionLine(WorkingDay);
                foreach (var z in newItems)
                {
                    _zaHuaItems[z.Id] = z;
                }

                // await LoadZaHuaSetAsync();
                OnZaHuaDataChanged();
            });
        }

        public void Del(List<ZuhuaRecord> os)
        {
            
            //2 dete 
            LongTask(()=>_rzu.Dels(os) ) ;
            
            LoadZaHuaSetAsync();
            LoadZuHuaSetAsync();
              
        }

        public ZuhuaRecord CopyToNew(ZuhuaRecord o)
        {
            if (o==null) o=new ZuhuaRecord();
            
            var a = o.ToJson().ToObject<ZuhuaRecord>();
            a.Id = 1.NewSnowflakeId();
            a.发货单码 = "不要改我";
            a.FaHuoZiLingItems.Clear();
            a.ZHTime=DateTime.Now;
            a.CreateTime= DateTime.Now;
            
            return a;
        }

        public void Add(ZuhuaRecord z)
        {
            if (z.FaHuoZiLingItems.Count < 1)
                throw new Exception("至少加一扎花");
            
            _rzu.FillKapiInfo(z);

            SaveAllAsync(new List<ZuhuaRecord>() { z });
            OnZuhuaDataChanged();
        }

        public List<ZaHuaItem> CopyOrCreateNewZaha(ZaHuaItem model)
        {
            ZaHuaItem re= null ;

            if (model == null)
            {
                re=    _rza.CreateNewZahua();
            }
            else
            {
                  re=model.ToJson().ToObject< ZaHuaItem >();

                  re.Id = 1.NewSnowflakeId();
                  re.IdBackPointer = re.Id;
                  re.供货日期 = DateTime.Now;
            }

              _rza.SaveEntityAsync(re);
            _zaHuaItems[re.Id] = re;
            
            OnZaHuaDataChanged();
            return new List<ZaHuaItem>() { re };
            

        }

        public void DelZas(IEnumerable<ZaHuaItem> zaHuaItems)
        {
            var re=zaHuaItems.Where(x => x.ZhiLingItemId != 0);
            if (re.Any())
                throw new Exception($"有【{re.Count()}】扎已经被组。删除失败！");
            
            _rza.Del(zaHuaItems);
            foreach (var z in zaHuaItems)
            {
                _zaHuaItems.TryRemove(z.Id, out _);
            }
            OnZaHuaDataChanged();
        }

        public void SaveZahua(ZaHuaItem za)
        {

            _rza.SaveEntityAsync(za);
        }

        public void SaveZahuas(IEnumerable<ZaHuaItem> os)
        {

            _rza.SaveEntitysAsync(os);
        }

        public void UpdateSelected(List<ZuhuaRecord> os, (bool selected, string value) lr, (bool selected, string value) fh)
        {
            foreach (var z in os)
            {
                if (lr.selected)
                {
                    z.录单人= lr.value;
                }
                
                if (fh.selected)
                {
                    z.复核人= fh.value;
                }
                
            }

            SaveAllAsync(os);
        }
    }
}